package ch.unifr.pai.twice.layout.client.mobile; /* * Copyright 2013 Oliver Schmid * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import ch.unifr.pai.twice.layout.client.DynamicLayout; import ch.unifr.pai.twice.module.client.TWICEModule; import ch.unifr.pai.twice.module.client.TWICEModuleController; import ch.unifr.pai.twice.mousecontrol.client.MobileKeyboard; import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.dom.client.Style.Display; import com.google.gwt.dom.client.Style.Float; import com.google.gwt.dom.client.Style.Position; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.event.dom.client.BlurEvent; import com.google.gwt.event.dom.client.BlurHandler; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.FocusEvent; import com.google.gwt.event.dom.client.FocusHandler; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.AbsolutePanel; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.RootLayoutPanel; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.SimpleLayoutPanel; import com.google.gwt.user.client.ui.Widget; /** * The mobile layout mechanism logic. The mobile layout contains a menu bar on the top, displaying a button on the top left to open a menu. The menu appears * from the left and presents the different components which are available. There is always only one * * @author Oliver Schmid * */ public class MobileInterface { static MobileResourceBundle RESOURCES = GWT.create(MobileResourceBundle.class); SimpleLayoutPanel main = new SimpleLayoutPanel(); private final static Map<String, Widget> components = new LinkedHashMap<String, Widget>(); private final static Map<String, AsyncCallback<Widget>> callbacks = new LinkedHashMap<String, AsyncCallback<Widget>>(); private static String currentcomponentname; private final FlowPanel controlbar = new FlowPanel(); Menu menu = new Menu(); Button others = new Button(); private final MobileKeyboard keyboardButton = new MobileKeyboard(); private final Button hideKeyboard = new Button(); private final AbsolutePanel keyboardPanel = new AbsolutePanel(); /** * Initializes the main components */ public MobileInterface() { RESOURCES.mobileLayoutStyle().ensureInjected(); controlbar.setStyleName("controlbar"); others.setStyleName(RESOURCES.mobileLayoutStyle().menuButton()); others.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { menu.show(); } }); others.getElement().getStyle().setDisplay(Display.INLINE); others.setWidth("auto"); others.getElement().getStyle().setFloat(Float.LEFT); keyboardPanel.getElement().getStyle().setFloat(Float.RIGHT); keyboardButton.addStyleName("mobileKeyboard"); hideKeyboard.addStyleName("mobileKeyboard"); keyboardPanel.add(hideKeyboard); keyboardPanel.add(keyboardButton); // hideKeyboard.setWidth("50px"); // hideKeyboard.setHeight("100%"); // keyboardButton.setWidth("50px"); // keyboardButton.setHeight("50px"); // keyboardPanel.setWidgetPosition(hideKeyboard, 0, 0); // keyboardPanel.setWidgetPosition(keyboardButton, 0, 0); hideKeyboard.getElement().getStyle().setDisplay(Display.NONE); keyboardButton.addFocusHandler(new FocusHandler() { @Override public void onFocus(FocusEvent event) { hideKeyboard.getElement().getStyle().setDisplay(Display.BLOCK); keyboardButton.getElement().getStyle().setDisplay(Display.NONE); } }); keyboardButton.addBlurHandler(new BlurHandler() { @Override public void onBlur(BlurEvent event) { hideKeyboard.getElement().getStyle().setDisplay(Display.NONE); keyboardButton.setValue(null); keyboardButton.getElement().getStyle().setDisplay(Display.BLOCK); } }); hideKeyboard.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { hideKeyboard.getElement().getStyle().setDisplay(Display.NONE); keyboardButton.setValue(null); keyboardButton.getElement().getStyle().setDisplay(Display.BLOCK); } }); controlbar.add(others); controlbar.add(keyboardPanel); } /** * Adds the top bar to the layout */ private void addControlBar() { DynamicLayout.getPanel().add(controlbar); controlbar.getElement().getStyle().setTop(0, Unit.PX); controlbar.getElement().getStyle().setHeight(40, Unit.PX); controlbar.getElement().getStyle().setLeft(0, Unit.PX); controlbar.getElement().getStyle().setRight(0, Unit.PX); controlbar.getElement().getStyle().setPosition(Position.ABSOLUTE); controlbar.getElement().getStyle().setDisplay(Display.BLOCK); currentWidget.getElement().getStyle().setMarginTop(40, Unit.PX); } private Widget currentWidget; /** * Switch to a specific component ({@link TWICEModule}). If the module has not been accessed yet, it is instantiated and the callback is invoked. * * @param componentName */ void switchComponent(String componentName) { RootLayoutPanel.get().clear(); if (componentName == null && components.keySet().size() > 0) { componentName = (String) components.keySet().toArray()[0]; } // Is it a not yet instantiated module? final TWICEModule module = modules.get(componentName); if (module != null) { // Then instantiate it and add it to the components final String moduleComponentName = componentName; TWICEModuleController.instantiateModule(module, new AsyncCallback<Widget>() { @Override public void onSuccess(Widget result) { if (currentWidget != null) TWICEModuleController.stop(currentWidget); components.put(moduleComponentName, result); modules.remove(moduleComponentName); AsyncCallback<Widget> callback = callbacks.get(moduleComponentName); if (callback != null) { callback.onSuccess(result); } switchToWidget(moduleComponentName, result); } @Override public void onFailure(Throwable caught) { Window.alert("Was not able to initialize module " + moduleComponentName); } }); } else { Widget w = components.get(componentName); if (w == null && components.size() > 0) { componentName = (String) components.keySet().toArray()[0]; w = components.get(componentName); } switchToWidget(componentName, w); } } /** * Hide the current widget if there is one and show the given component on the single screen * * @param componentName * @param w */ private void switchToWidget(String componentName, Widget w) { if (w != null) { boolean issamewidget = currentWidget == w; if (currentWidget != null) { if (!issamewidget) TWICEModuleController.stop(currentWidget); currentWidget.removeFromParent(); } currentWidget = w; currentcomponentname = componentName; TWICEModule m = TWICEModuleController.getTWICEModule(currentWidget); if (m != null && m.attachToRootPanel(currentWidget)) { RootPanel.get().add(w); } else { RootLayoutPanel.get().add(w); } if (!issamewidget) TWICEModuleController.start(currentWidget); } Scheduler.get().scheduleDeferred(new ScheduledCommand() { @Override public void execute() { addControlBar(); } }); } boolean initialized; /** * Adds a component - if it is the first one, it will be directly shown on the main screen (initialized) * * @param componentName * @param component */ public void addComponent(String componentName, Widget component) { components.put(componentName, component); if (!initialized) { switchComponent(componentName); initialized = true; } // menu.addEntry(componentName); } /** * A map of registered modules (used to lookup for lazy instantiation) */ private static Map<String, TWICEModule<? extends Widget>> modules = new LinkedHashMap<String, TWICEModule<? extends Widget>>(); /** * Adds the module with the given name to the layout * * @param moduleName * @param module * @param callback */ public void addModule(String moduleName, TWICEModule<? extends Widget> module, AsyncCallback<? extends Widget> callback) { modules.put(moduleName, module); components.put(moduleName, null); callbacks.put(moduleName, (AsyncCallback<Widget>) callback); } /** * The menu that appears from the left if the menu button is pressed * * @author Oliver Schmid * */ public class Menu extends FlowPanel { Map<String, Label> menuButtons = new HashMap<String, Label>(); public Menu() { // setWidth("240px"); addStyleName(RESOURCES.mobileLayoutStyle().menu()); // getElement().getStyle().setHeight(100, Unit.PCT); // getElement().getStyle().setBackgroundColor("#2E2E2E"); // getElement().getStyle().setZIndex(10001); // getElement().getStyle().setBorderWidth(0, Unit.PX); } /** * Hide the menu */ public void hide() { removeFromParent(); } /** * Show the menu */ public void show() { clear(); for (String s : components.keySet()) { final String name = s; final Label b = new Label(name); menuButtons.put(name, b); b.getElement().getStyle().setColor("#ffffff"); b.getElement().getStyle().setFontSize(16, Unit.PX); b.getElement().getStyle().setMargin(5, Unit.PX); b.getElement().getStyle().setPadding(10, Unit.PX); b.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { if (currentcomponentname != null) { Label old = menuButtons.get(currentcomponentname); if (old != null) old.removeStyleName(RESOURCES.mobileLayoutStyle().selectedMenuEntry()); } switchComponent(name); b.setStyleName(RESOURCES.mobileLayoutStyle().selectedMenuEntry()); Menu.this.hide(); } }); if (s.equals(currentcomponentname)) { b.setStyleName(RESOURCES.mobileLayoutStyle().selectedMenuEntry()); } add(b); } if (currentWidget != null) { currentWidget.getElement().getStyle().setLeft(240, Unit.PX); } controlbar.getElement().getStyle().setLeft(240, Unit.PX); DynamicLayout.getPanel().add(this); } } }